package com.testmall.utils;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.testmall.entity.common.TokenProperties;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.*;

/**
 * @Description: tokenUtil 工具类
 * @Author: littleDesire
 * @Date: 2022-06-22 16:32
 * @Version: 1.0
 */
public class TokenUtil {
    @Autowired
    TokenProperties tokenProperties;

    /**
     * 生成token
     *
     * @return token
     */
    public String generateToken(Map<String, Object> map) {
        return JWT.create()
                // Header：有令牌的类型和所使用的签名算法，如HMAC、SHA256、RSA；使用Base64编码组成
                .withHeader(header())
                // Payload ：有效负载，包含声明；声明是有关实体（通常是用户）和其他数据的声明，不放用户敏感的信息，如密码。
                .withPayload(parsePayload(map))
                // 向有效负载添加特定的颁发者（“iss”）声明
                .withIssuer("米奇妙妙屋")
                // 设置过期时间
                .withExpiresAt(expiresDate())
                // Signature ：前面两部分都使用Base64进行编码，前端可以解开知道里面的信息。Signature需要使用编码后的header和payload
                // 加上我们提供的一个密钥，使用header中指定的签名算法(HS256)进行签名。签名的作用是保证JWT没有被篡改过
                .sign(Algorithm.HMAC256(tokenProperties.getSecret()));
    }

    /**
     * 对token进行验证
     *
     * @param token token
     * @return payload 信息
     */
    public Map<String, Object> verifyToken(String token) {
        JWTVerifier verifier = JWT.require(Algorithm.HMAC256(tokenProperties.getSecret()))
                .withIssuer("米奇妙妙屋")
                .build();
        DecodedJWT decodedJwt;
        Map<String, Object> map = new HashMap<>();
        try {
            decodedJwt = verifier.verify(token);
        } catch (Exception e) {
            e.printStackTrace();
            String msg = e.toString();
            if (msg.contains("The Token has expired")) {
                map.put("code", 1);
                map.put("msg", "Token已过期");
                return map;
            }
            map.put("code", 0);
            map.put("msg", "Token无效");
            return map;
        }
        map.put("code", 200);
        map.put("msg", "Token验证通过");
        map.put("payload", decodedJwt.getClaims());
        return map;
    }

    /**
     * 计算token有效时间 单位分钟
     *
     * @return token过期时间
     */
     Date expiresDate() {
        long time =(long) tokenProperties.getValidateTime() * 1000 * 60;
        return new Date(System.currentTimeMillis() + time);
    }

    /**
     * 解析有效载荷
     * 判断map中是否含有正确的 X-token 及 值
     * 对map做一个判断，当有key和value时才放入到map当中
     *
     * @param map 旧的map
     * @return 新的map
     */
     Map<String, Object> parsePayload(Map<String, Object> map) {
        Map<String, Object> rsMap = new HashMap<>();
        Set<Map.Entry<String, Object>> set = map.entrySet();
        for (Map.Entry<String, Object> entry : set) {
            if (null != entry.getKey() && null != entry.getValue()) {
                rsMap.put(entry.getKey(), entry.getValue());
            }
        }
        return rsMap;
    }

    /**
     * @return Header：有令牌的类型和所使用的签名算法
     */
    private  Map<String, Object> header() {
        Map<String, Object> map = new HashMap<>();
        map.put("type", "JWT");
        map.put("alg", "HMAC256");
        return map;
    }
}
